#pragma once
#include <xutility>
#include <type_traits>
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif

static const size_t no_value = (size_t)-1;

template<class _Ty>
class range
{	
public:
    typedef range<_Ty> _Myt;
    typedef _Ty     value_type;

    typedef typename _STD iterator_traits<_Ty> iter_traits;
    typedef typename iter_traits::difference_type   difference_type;
    typedef typename iter_traits::distance_type   distance_type;

protected:
    value_type _first;	// the beginning of range
    value_type _second;	// the end of range

public:
    inline value_type  getFirst() const throw()
    {
        return _first;
    }

    inline void  setFirst(value_type value_) throw()
    {
        if (_second < (_first = value_))
            _second = _first;
    }

    inline value_type  getSecond() const throw()
    {
        return _second;
    }

    inline void setSecond(value_type value_) throw()
    {
        if (_first > (_second = value_)) 
            _first = _second;
    }

    value_type  __declspec(property (get=getFirst, put=setFirst))
        first;
    value_type  __declspec(property (get=getSecond, put=setSecond))
        second;

    inline 
    _Myt& normalize() throw()
    {
        if (_first > _second)
            _STD swap(_first, _second);
        return *this;
    }

    inline
    bool    verify() const throw()
    {
        return _first <= _second;
    }

    inline
    bool    empty() const throw()
    {
        return _first == _second;
    }

    inline
    operator bool() const throw()
    {
        return (_first < _second);
    }

    inline
    _Myt&   operator++() throw()
    {
        if (_first < _second)
            ++_first;

        return *this;
    }

    inline
    _Myt   operator++(int) throw()
    {
        _Myt ret(*this);
        operator++();
        return (ret);
    }

    inline
    _Myt&   assign(const _Ty _1, const _Ty _2) throw()
    {
        _first = _1;
        _second = _2;
        return normalize();
    }

    inline
    _Myt&   assign(const _Ty _1) throw()
    {
        _first = _second = _1;
        return *this;
    }

    __forceinline
    range() throw()
	    : _first(_Ty())
        , _second(first)
	{	// construct from defaults
	}

    __forceinline
    range(const _Ty& _1)  throw()
	    : _first(_1)
        , _second(_1)
	{	// construct from single value
	}

    __forceinline
    range(const _Ty& _1, const _Ty& _2) throw()
	    : _first(_1)
        , _second(_2)
	{	// construct from specified values
        normalize();
	}

    template<class _Other>
    __forceinline
	range(const range<_Other>& ref_) throw()
	    : _first(ref_.first)
        , _second(ref_.second)
	{	// construct from compatible range
        normalize();
	}

    void swap(_Myt& ref_) throw()
	{	// exchange contents with ref_
	    if (this != &ref_)
		{	// different, worth swapping
		    _STD _Swap_adl(_first, ref_._first);
		    _STD _Swap_adl(_second, ref_._second);
		}
	}

    inline
    bool has(const _Ty value_) const throw()
    {
        return ((value_ < _second) && (value_ >= _first));
    }

    inline
    bool overlap(const _Myt& ref_) const throw()
    {
        return (ref_._first < _second) && (_first < ref_._second);
    }

    inline
    bool adjoin(const _Myt& ref_) const throw()
    {
        return (ref_._first == _second) || (_first == ref_._second);
    }

    inline
    bool overlap_or_adjoin(const _Myt& ref_) const throw()
    {
        return (ref_._first <= _second) && (_first <= ref_._second);
    }

    inline
    _Myt& operator=(const _Ty _1) throw()
    {
        return assign(_1);
    }

    inline
    _Myt& operator=(const _Myt& ref_) throw()
    {
        return assign(ref_._first, ref_._second);
    }

    inline
    _Myt&   advance(distance_type delta_ ) 
    {
        _first += delta_;
        if (_first > _second)
            _first = _second;
        return *this;
    }

    inline
    _Myt& grow(distance_type delta_ ) 
    {
        _second += delta_;
        return *this;
    }

    inline
    _Myt& reduce(distance_type delta_ ) 
    {
        _second -= delta_;
        if (_second < _first)
            _second = _first;
        return *this;
    }

    inline
    distance_type  length() const throw()
    {
        return (distance_type(_second - _first));
    }

    _Myt intersection(const _Myt& ref_) const throw()
    {
        if (ref_.has(_first))
            return (_Myt(_first, _STD min(_second, ref_._second)));
        else if (has(ref_._first))
            return (_Myt(ref_._first, _STD min(_second, ref_._second)));
        return (_Myt());
    }

    _Myt   subrange(size_t off_ = 0, size_t count_ = no_value) const throw()
    {
        return (intersection(_first + off_, _first + off_ + count_));
    }

    _Myt   left(size_t at_) const throw()
    {
        _Myt ret(_first, _first + at_);
        if (!has(ret._second))
        {
            ret._second = _second;
        }

        return (ret);
    }

    _Myt   right(size_t at_) const throw()
    {
        _Myt ret(_first + at_, _second);
        if (!has(ret._second))
        {
            ret._second = _second;
        }

        return (ret);
    }


    _Myt   split_left(const _Ty at_) throw()
    {
        _Myt ret(_first);
        if (has(at_))
        {
            ret._second = _first =_at;
        }

        return (ret);
    }

    _Myt   split_right(const _Ty at_) throw()
    {
        _Myt ret(_second);
        if (has(at_))
        {
            ret._first = _second = at_;
        }

        return (ret);
    }
};

// ranges TEMPLATE FUNCTIONS

template<class CharType, class Traits>
_STD basic_ostream<CharType, Traits>& operator<<(
  _STD basic_ostream<CharType, Traits>& _Ostr,
  const range<const CharType*>& _Str)
{
    return _Ostr.write(_Str.first, _Str.second - _Str.first);
}

template<class _Ty> 
inline void swap(range<_Ty>& _Left, range<_Ty>& _Right)
{	// swap _Left and _Right ranges
    _Left.swap(_Right);
}

template<class _Ty> 
inline bool operator==(const range<_Ty>& _Left,
	const range<_Ty>& _Right)
{	// test for range equality
    return (_Left.first == _Right.first && _Left.second == _Right.second);
}

template<class _Ty> 
inline bool operator!=(const range<_Ty>& _Left,
	const range<_Ty>& _Right)
{	// test for range inequality
    return (!(_Left == _Right));
}

template<class _Ty> 
inline bool operator<(const range<_Ty>& _Left,
	const range<_Ty>& _Right)
{	// test if _Left < _Right for ranges
    return (_Left.first < _Right.first ||
	!(_Right.first < _Left.first) && _Left.second < _Right.second);
}

template<class _Ty> 
inline bool operator>(const range<_Ty>& _Left,
	const range<_Ty>& _Right)
{	// test if _Left > _Right for ranges
    return (_Right < _Left);
}

template<class _Ty> 
inline bool operator<=(const range<_Ty>& _Left,
	const range<_Ty>& _Right)
{	// test if _Left <= _Right for ranges
    return (!(_Right < _Left));
}

template<class _Ty> 
inline bool operator>=(const range<_Ty>& _Left,
	const range<_Ty>& _Right)
{	// test if _Left >= _Right for ranges
    return (!(_Left < _Right));
}

template<class _Ty> 
inline range<_Ty> make_range(const _Ty _1, const _Ty _2)
{	// return range composed from arguments
    return (range<_Ty>(_1, _2));
}

